Use case: FIR or IIR (ADC input X1, DMA output Y) ¶
This use case shows an FMAC FIR/IIR filter where the X1 input FIFO is fed by the ADC (external peripheral) and the Y output FIFO is read in DMA mode.
Sequence diagram ¶
Code snippet ¶
|
HAL1 |
HAL2 |
|---|---|
ADC_MultiModeTypeDef multimode = {0};
ADC_ChannelConfTypeDef sConfig = {0};
/* FMAC WDATA register address (for DMA transfer) */
#define FMAC_WDATA (0x40021418)
hadc1.Instance = ADC1;
hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.DataAlign = ADC_DATAALIGN_LEFT;
hadc1.Init.GainCompensation = 0;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc1.Init.LowPowerAutoWait = DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.NbrOfConversion = 1;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIG_HRTIM_TRG1;
hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING;
hadc1.Init.DMAContinuousRequests = ENABLE;
hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
hadc1.Init.OversamplingMode = DISABLE;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
multimode.Mode = ADC_MODE_INDEPENDENT;
if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
{
Error_Handler();
}
sConfig.Channel = ADC_CHANNEL_4;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
sConfig.SingleDiff = ADC_SINGLE_ENDED;
sConfig.OffsetNumber = ADC_OFFSET_1;
sConfig.Offset = REF;
sConfig.OffsetSign = ADC_OFFSET_SIGN_NEGATIVE;
sConfig.OffsetSaturation = DISABLE;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
HAL_FMAC_Init(&hfmac);
sFmacConfig.InputBaseAddress = INPUT_BUFFER_BASE;
sFmacConfig.InputBufferSize = INPUT_BUFFER_SIZE;
sFmacConfig.InputThreshold = INPUT_THRESHOLD;
sFmacConfig.CoeffBaseAddress = COEFFICIENT_BUFFER_BASE;
sFmacConfig.CoeffBufferSize = COEFFICIENT_BUFFER_SIZE;
sFmacConfig.OutputBaseAddress = OUTPUT_BUFFER_BASE;
sFmacConfig.OutputBufferSize = OUTPUT_BUFFER_SIZE;
sFmacConfig.OutputThreshold = OUTPUT_THRESHOLD;
sFmacConfig.pCoeffA = aFilterCoeffA;
sFmacConfig.CoeffASize = COEFF_VECTOR_A_SIZE;
sFmacConfig.pCoeffB = aFilterCoeffB;
sFmacConfig.CoeffBSize = COEFF_VECTOR_B_SIZE;
sFmacConfig.Filter = FMAC_FUNC_IIR_DIRECT_FORM_1;
sFmacConfig.InputAccess = FMAC_BUFFER_ACCESS_NONE;
sFmacConfig.OutputAccess = FMAC_BUFFER_ACCESS_DMA;
sFmacConfig.Clip = FMAC_CLIP_DISABLED;
sFmacConfig.P = COEFF_VECTOR_B_SIZE;
sFmacConfig.Q = COEFF_VECTOR_A_SIZE;
sFmacConfig.R = GAIN;
HAL_FMAC_FilterConfig(&hfmac, &sFmacConfig);
HAL_FMAC_FilterStart(&hfmac, Output, OutputDataSize);
/* Assign FMAC Write Data register (@WDATA) to Fmac_Wdata */
Fmac_Wdata = (uint32_t *) FMAC_WDATA;
/* Start ADC and DMA */
HAL_ADC_Start_DMA(&hadc1, Fmac_Wdata, OUTPUT_BUFFER_SIZE*4);
HAL_FMAC_FilterStop(&hfmac);
HAL_FMAC_DeInit(&gh_fmac);
|
hal_adc_config_t adc_config;
HAL_ADC_Init(&hADC1, HAL_ADC1);
adc_config.resolution = HAL_ADC_RESOLUTION_12_BIT;
adc_config.sampling_mode = HAL_ADC_SAMPLING_MODE_NORMAL;
HAL_ADC_SetConfig(&hADC1, &adc_config);
hal_adc_reg_config_t reg_config;
reg_config.trigger_src = HAL_ADC_REG_TRIG_SOFTWARE_START;
reg_config.trigger_edge = HAL_ADC_REG_TRIG_EDGE_NONE;
reg_config.sequencer_length = 1;
reg_config.sequencer_discont = HAL_ADC_REG_SEQ_DISCONT_DISABLE;
reg_config.continuous = HAL_ADC_REG_CONV_SINGLE;
reg_config.overrun = HAL_ADC_REG_OVR_DATA_OVERWRITTEN;
reg_config.data_transfer = HAL_ADC_REG_DATA_TRANSFER_NONE;
HAL_ADC_REG_SetConfig(&hADC1, ®_config);
hal_adc_channel_config_t adc_channel_config;
adc_channel_config.group = HAL_ADC_GROUP_REGULAR;
adc_channel_config.sequencer_rank = 1;
adc_channel_config.input_mode = HAL_ADC_IN_SINGLE_ENDED;
adc_channel_config.sampling_time = HAL_ADC_SAMPLING_TIME_2CYCLES_5;
HAL_ADC_SetConfigChannel(&hADC1, HAL_ADC_CHANNEL_4, &adc_channel_config);
HAL_FMAC_Init(&hfmac, (hal_fmac_t)FMAC);
sFmacConfig.x1_buf.base_half_word = INPUT_BUFFER_BASE;
sFmacConfig.x1_buf.size_half_word = INPUT_BUFFER_SIZE;
sFmacConfig.x2_buf.base_half_word = COEFFICIENT_BUFFER_BASE;
sFmacConfig.x2_buf.size_half_word = COEFFICIENT_BUFFER_SIZE;
sFmacConfig.y_buf.base_half_word = COEFFICIENT_BUFFER_SIZE;
sFmacConfig.y_buf.size_half_word = OUTPUT_BUFFER_BASE;
HAL_FMAC_SetConfig(&hfmac, &sFmacConfig);
data.coeff_a_size_half_word = COEFF_VECTOR_A_SIZE;
data.p_coeff_a = aFilterCoeffA;
data.coeff_b_size_half_word = COEFF_VECTOR_B_SIZE;
data.p_coeff_b = aFilterCoeffB;
HAL_FMAC_PreloadX2(&hfmac, &data);
/* Obtain the FMAC Write Data register (@WDATA) for ADC */
Fmac_Wdata = HAL_FMAC_GetX1Address(&hfmac);
HAL_FMAC_LockX1WriteAccessForExternPeriph(&hfmac);
HAL_FMAC_ReadY_DMA(&hfmac, Output, OutputDataSize);
HAL_FMAC_StartFilterIIR(&hfmac, COEFF_VECTOR_B_SIZE, COEFF_VECTOR_A_SIZE, GAIN, HAL_FMAC_OPT_IT_FILTER_SATURATION_ERROR);
/* Start ADC and DMA toward FMAC X1 */
HAL_ADC_Start(hadc1);
HAL_ADC_REG_StartConv_DMA(hadc1, (uint8_t const *)Fmac_Wdata, OUTPUT_BUFFER_SIZE*4);
HAL_FMAC_StopFilter(&hfmac);
HAL_FMAC_UnlockX1WriteAccessForExternPeriph(&hfmac);
HAL_FMAC_DeInit(&gh_fmac);
|
Key changes ¶
HAL2 supports external-peripheral feeding of X1 by providing helpers such as
HAL_FMAC_GetX1Address()and explicit lock/unlock of X1 write access for external peripherals.HAL2 keeps the Y DMA read flow explicit through
HAL_FMAC_ReadY_DMA()and completion callbacks.
![@startuml
title: FIR filter with :\n - input/X1 managed by the ADC driver \n - output/Y managed with DMA process
participant App as "User application"
participant App
participant "<font color=Black><b>HAL FMAC</b></font>" as FMAC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "<font color=red><b>HAL ADC</b></font>" as ADC
participant "FMACx_IRQHandler"
participant "DMAx_IRQHandler"
App -> ADC : HAL_ADC_Init
App <-- ADC : HAL_OK
App -> FMAC : HAL_FMAC_Init
App <-- FMAC : HAL_OK
group ADC System initialization: can be called before ADC HAL initialization
App -[hidden]>ADC
end
group FMAC System initialization: can be called before FMAC HAL initialization
App -[hidden]>FMAC
end
App -> FMAC : HAL_FMAC_FilterConfig()
note right : The ADC management configuration for input X1 is carried out in this function by setting FMAC_BUFFER_ACCESS_NONE\nin the InputAccess parameter within FMAC_FilterConfigTypeDef structure.\nThe DMA mode configuration for output Y is carried out in this function by setting FMAC_BUFFER_ACCESS_DMA\nin the OutputAccess parameter within FMAC_FilterConfigTypeDef structure.
App <-- FMAC : HAL_OK
App -> FMAC : HAL_FMAC_AppendFilterData()
App <-- FMAC : HAL_OK
App -> FMAC : HAL_FMAC_FilterStart()
App <-- FMAC :HAL_OK
App -> ADC : HAL_ADC_Start_DMA
note right : Start ADC conversion and store the result in FMAC Write Data register address (@WDATA)
App <-- ADC : HAL_OK
"DMAx_IRQHandler" <- : DMAx half complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> ADC : XferCpltCallback
ADC-> App : HAL_ADC_ConvHalfCpltCallback()
"DMA" <-- ADC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> ADC : XferCpltCallback
ADC-> App : HAL_ADC_ConvCpltCallback()
"DMA" <-- ADC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx half complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> FMAC : XferCpltCallback
FMAC-> App : HAL_FMAC_HalfOutputDataReadyCallback()
"DMA" <-- FMAC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> FMAC : XferCpltCallback
FMAC-> App : HAL_FMAC_OutputDataReadyCallback()
"DMA" <-- FMAC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
App -> FMAC : HAL_FMAC_FilterStop()
App <-- FMAC :HAL_OK
App->FMAC : HAL_FMAC_DeInit()
App<--FMAC
@enduml](../../../../../_images/plantuml-8e5dad4534d3e3e3eb1920f71ace147ffe1dd9d0.png)
![@startuml
title: FIR filter with :\n - input/X1 managed by the ADC driver \n - output/Y managed with DMA process
participant App as "User application"
participant App
participant "<font color=Black><b>HAL FMAC</b></font>" as FMAC
participant "<font color=green><b>HAL DMA</b></font>" as DMA
participant "<font color=red><b>HAL ADC</b></font>" as ADC
participant "FMACx_IRQHandler"
participant "DMAx_IRQHandler"
App -> ADC : HAL_ADC_Init
App <-- ADC : HAL_OK
App -> FMAC : HAL_FMAC_Init
App <-- FMAC : HAL_OK
group ADC System initialization: can be called before ADC HAL initialization
App -[hidden]>ADC
end
group FMAC System initialization: can be called before FMAC HAL initialization
App -[hidden]>FMAC
end
App -> FMAC : HAL_FMAC_SetConfig
App <-- FMAC :HAL_OK
==Advanced FMAC Configuration (optional)==
App -> FMAC : HAL_FMAC_SetX1FullWatermark
App <-- FMAC :HAL_OK
App -> FMAC : HAL_FMAC_SetYEmptyWatermark
App <-- FMAC :HAL_OK
App -> FMAC : HAL_FMAC_EnableClip
App <-- FMAC :HAL_OK
note over App : Driver state is IDLE,\nUser can start any process or execute any configuration
== FIR filter with :\n - input/X1 managed directly by ADC periph\n - output/Y managed with DMA process ==
note over App : Preload of filter coefficients
App -> FMAC : HAL_FMAC_PreloadX2
App <-- FMAC :HAL_OK
note over App : Get Write Register address.
App -> FMAC : HAL_FMAC_GetX1Address
note right : This function obtains the address of the FMAC Write Data register address (@WDATA), which is then used as the destination\nfor ADC conversion data in the HAL_ADC_REG_StartConv_DMA function.
App <-- FMAC :HAL_OK
App -> FMAC : HAL_FMAC_LockX1WriteAccessForExternPeriph
note right : Update the state of X1 fifo to protect the FMAC driver against accidental\ncalls to the Write X1 APIs in case of input data managed by an external peripheral
App <-- FMAC :HAL_OK
App -> FMAC : HAL_FMAC_ReadY_DMA
note right : Read data from Y in DMA mode
App <-- FMAC :HAL_OK
App -> FMAC : HAL_FMAC_StartFilterFIR or HAL_FMAC_StartFilterIIR
App <-- FMAC :HAL_OK
App -> ADC : HAL_ADC_Start
App <-- ADC : HAL_OK
App -> ADC : HAL_ADC_REG_StartConv_DMA
note right : Start ADC conversion and store the result in FMAC Write Data register address (@WDATA) via DMA\nthe address is recuperated from HAL_FMAC_GetX1Address function
App <-- ADC : HAL_OK
"DMAx_IRQHandler" <- : DMAx half complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> ADC : XferCpltCallback
ADC-> App : HAL_ADC_REG_DataTransferHalfCallback()
"DMA" <-- ADC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler()
"DMA" -> ADC : XferCpltCallback
ADC-> App : HAL_ADC_REG_DataTransferCpltCallback()
"DMA" <-- ADC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx half complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler
"DMA" -> FMAC : XferCpltCallback
FMAC-> App : HAL_FMAC_ReadYHalfCpltCallback
"DMA" <-- FMAC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
"DMAx_IRQHandler" <- : DMAx complete interrupt
"DMAx_IRQHandler" -> "DMA" : HAL_DMA_IRQHandler
"DMA" -> FMAC : XferCpltCallback
FMAC-> App : HAL_FMAC_ReadYCpltCallback
"DMA" <-- FMAC
"DMAx_IRQHandler" <-- "DMA"
"DMAx_IRQHandler" -->
note over App : Y state is IDLE,\nUser can start any Read Y process.
App -> FMAC : HAL_FMAC_UnlockX1WriteAccessForExternPeriph
note right : Update the state of X1 fifo to unlock the FMAC driver protection that prevents calls to Write X1 APIs
App <-- FMAC :HAL_OK
note over App : X1 state is IDLE,\nUser can start any Read Y process.
App -> FMAC : HAL_FMAC_StopFilter()
App <-- FMAC :HAL_OK
note over App : Filter state is IDLE,\nUser can start any filter or preload process
App->FMAC : HAL_FMAC_DeInit
App<--FMAC
@enduml](../../../../../_images/plantuml-98ae9ee285ebcc178a7fda42d8ce7a22dab7c3b7.png)